<script lang="ts" setup>
import { computed, onMounted, ref, watch } from 'vue';
import { Project } from './Project';
import type { ProjectInfo } from '@/types/ProjectInfo';
import { sleepAsync, isNullOrEmpty } from '@/utils/test-api';
import { ElMessage } from 'element-plus';
import {
  deletePollingTaskAsync,
  getPartsAsync,
  getPollingTasksAsync,
  insertPollingTaskAsync
} from '@/utils/project-api';
import { PartInfo } from '@/types/PartInfo';
import { CirclePlusFilled } from '@element-plus/icons-vue';
import { getConfigsAsync } from '@/utils/device-server-client';
import { showDeleteMessageBoxAsync } from '@/utils/message-box';
import { PollingTask } from '@/types/PollingTask';
import type { DeviceConfig } from '@/types/Device';
import { dataTypes } from '@/constants/device-server-client';

const project = new Project();
const currentProjectName = ref('');
const loadingText = ref('正在加载项目列表...');
const dialogLoadingText = ref('正在加载任务列表...');
const isLoading = ref(false);
const projects = ref<ProjectInfo[]>([]);
const parts = ref<PartInfo[]>([]);
const dialogIsLoading = ref(false);
const pageIndex = ref(0);
const pageSize = 50;
const currentPartName = ref('');
const tasks = ref<PollingTask[]>([]);

const taskName = ref('');
const deviceName = ref('');
const address = ref('');
const interval = ref<number>(500);
const dataType = ref('');
const enable = ref(true);
const published = ref(true);

const deviceConfigurations = ref<DeviceConfig[] | null>(null);

function resetProps() {
  taskName.value = '';
  deviceName.value = '';
  address.value = '';
  interval.value = 500;
  dataType.value = '';
  enable.value = true;
  published.value = true;
}

const disableOperationButton = computed(() => {
  return (
    currentPartName.value == null ||
    currentPartName.value == '' ||
    currentPartName.value == undefined
  );
});
const showAddPartDialog = ref(false);

function openDialogLoading() {
  dialogIsLoading.value = true;
}

function closeDialogLoading() {
  dialogIsLoading.value = false;
}

// 打开添加任务对话框页面时，初始化设备节点列表
async function onOpenAddPartDialogAsync() {
  if (deviceConfigurations.value != null) {
    return;
  }
  await updateDeviceNamesAsync();
}

function openLoading() {
  // 如果对话框 loading 了，则不加载页面 loading
  if (!dialogIsLoading.value) isLoading.value = true;
}

function closeLoading() {
  isLoading.value = false;
}

watch(currentProjectName, async (newValue) => {
  if (newValue != null && newValue != '' && newValue != undefined) {
    await updatePartsAsync();
  }
});

watch(currentPartName, async (newValue) => {
  if (newValue != null && newValue != '' && newValue != undefined) {
    await updatePollingTaskAsync();
  }
});

onMounted(() => {
  updateProjectsAsync();
});

// 更新项目列表
async function updateProjectsAsync() {
  loadingText.value = '正在加载项目列表...';
  try {
    openLoading();
    await sleepAsync(500);
    projects.value = await project.getAsync(pageIndex.value * pageSize, pageSize);
  } catch (err) {
    const message = err as string;
    if (message != null) {
      ElMessage.warning(message);
    } else {
      console.error(err);
      ElMessage.error('获取项目列表错误！');
    }
  } finally {
    closeLoading();
  }
}

// 更新部件列表
async function updatePartsAsync() {
  loadingText.value = '正在加载部件...';
  openLoading();
  try {
    const currentProject = projects.value.find(
      (item) => item.projectName == currentProjectName.value
    );
    await sleepAsync(500);
    const result = await getPartsAsync(currentProject!.id);
    if (result.isSuccess) {
      const partArray = result.result ?? [];
      parts.value = partArray.map((item) => {
        const partInfo: PartInfo = {
          ...item,
          partOwnerName:
            item.partOwnerId == null
              ? ''
              : partArray.find((partItem) => partItem.id == item.partOwnerId)?.partName ?? ''
        };
        return partInfo;
      });
    } else {
      throw result.message;
    }
  } catch (err) {
    const message = err as string;
    if (message != null) {
      ElMessage.warning(message);
    } else {
      console.error(err);
      ElMessage.error('获取部件列表错误！');
    }
  } finally {
    closeLoading();
  }
}

// 更新轮训任务列表
async function updatePollingTaskAsync() {
  dialogLoadingText.value = '正在加载任务...';
  const currentPart = parts.value.find((item) => item.partName == currentPartName.value);
  try {
    openLoading();
    await sleepAsync(500);
    const taskResult = await getPollingTasksAsync(currentPart!.id);
    if (taskResult.isSuccess) {
      tasks.value = taskResult.result ?? [];
    } else {
      throw taskResult.message;
    }
  } catch (err) {
    const message = err as string;
    if (message != null) {
      ElMessage.warning(message);
    } else {
      console.error(err);
      ElMessage.error('获取任务列表错误！');
    }
  } finally {
    closeLoading();
  }
}

function onDialogBeforeClose(done: any) {
  if (dialogIsLoading.value) {
    ElMessage.info('正在添加新的部件...');
  }
  // 对话框正在加载时，不关闭对话框
  done(dialogIsLoading.value);
}

async function updateDeviceNamesAsync() {
  dialogLoadingText.value = '正在加载设备名列表...';
  const currentPart = parts.value.find((item) => item.partName == currentPartName.value);
  openDialogLoading();
  await sleepAsync(500);
  try {
    const configurationResult = await getConfigsAsync(currentPart!.deviceId);

    if (configurationResult.isSuccess) {
      deviceConfigurations.value = configurationResult.result ?? [];
    } else {
      throw configurationResult.message;
    }
  } catch (err) {
    const message = err as string;
    if (message != null) {
      ElMessage.warning(message);
    } else {
      console.error(err);
      ElMessage.error('获取任务列表错误！');
    }
  } finally {
    closeDialogLoading();
  }
}

async function onAddPollingTaskAsync() {
  if (
    isNullOrEmpty(taskName.value) ||
    isNullOrEmpty(deviceName.value) ||
    isNullOrEmpty(address.value)
  ) {
    ElMessage.info('参数不能为空');
    return;
  } else if (interval.value < 200) {
    ElMessage.info('扫描周期不得小于200ms');
    return;
  }

  dialogLoadingText.value = '正在添加任务...';
  try {
    openDialogLoading();
    const result = await insertPollingTaskAsync({
      taskName: taskName.value,
      deviceName: deviceName.value,
      dataType: dataType.value,
      address: address.value,
      interval: interval.value,
      enable: enable.value,
      published: published.value,
      partId: parts.value.find((item) => item.partName == currentPartName.value)!.id
    } as PollingTask);

    if (result.isSuccess) {
      await updatePollingTaskAsync();
      resetProps();
      showAddPartDialog.value = false;
    } else {
      throw result.message;
    }
  } catch (err) {
    const message = err as string;
    if (message != null) {
      ElMessage.warning(message);
    } else {
      console.error(err);
      ElMessage.error('添加任务错误！');
    }
  } finally {
    closeDialogLoading();
  }
}

async function onDeleteTaskAsync(index: number) {
  if (!(await showDeleteMessageBoxAsync())) {
    return;
  }
  const taskId = tasks.value[index].id!;

  loadingText.value = '正在删除任务...';
  openLoading();

  try {
    await deletePollingTaskAsync(taskId);
    await updatePollingTaskAsync();
  } catch (err) {
    const message = err as string;
    if (message != null) {
      ElMessage.warning(message);
    } else {
      console.error(err);
      ElMessage.error('删除任务错误！');
    }
  } finally {
    closeLoading();
  }
}
</script>
  
<template>
  <main class="main-container" v-loading="isLoading" :element-loading-text="loadingText">
    <div class="main-content">
      <div class="search-bar">
        <div class="select-container">
          <div>
            <el-text>项目名称：</el-text>
            <el-select
              v-model="currentProjectName"
              class="select-layout"
              filterable
              placeholder="请选择项目"
            >
              <el-option
                v-for="projectInfo in projects"
                :key="projectInfo.id"
                :label="projectInfo.projectName"
                :value="projectInfo.projectName"
              ></el-option>
            </el-select>
          </div>
          <div class="select-margin">
            <el-text>部件名称：</el-text>
            <el-select
              v-model="currentPartName"
              class="select-layout"
              filterable
              placeholder="请选择部件"
            >
              <el-option
                v-for="partItem in parts"
                :key="partItem.id"
                :label="partItem.partName"
                :value="partItem.partName"
              ></el-option>
            </el-select>
          </div>
        </div>
        <div>
          <el-button
            type="primary"
            :icon="CirclePlusFilled"
            :disabled="disableOperationButton"
            @click="showAddPartDialog = true"
            >新增</el-button
          >
        </div>
      </div>
      <el-divider />
      <div class="table-content">
        <el-table :data="tasks" class="table">
          <el-table-column fixed prop="taskName" label="任务名称" />
          <el-table-column fixed prop="deviceName" label="设备名称" />
          <el-table-column fixed prop="address" label="地址" />
          <el-table-column prop="dataType" label="数据类型" />
          <el-table-column prop="interval" label="周期" />
          <el-table-column prop="enable" label="任务状态" />
          <el-table-column prop="published" label="发布状态" />
          <el-table-column fixed="right" label="操作" width="120">
            <template #default="scope">
              <el-button
                link
                type="primary"
                size="small"
                @click.prevent="onDeleteTaskAsync(scope.$index)"
              >
                删除
              </el-button>
            </template>
          </el-table-column>
        </el-table>
      </div>
    </div>
    <el-dialog
      v-model="showAddPartDialog"
      title="添加新任务"
      width="400"
      :close-on-click-modal="false"
      draggable
      :before-close="onDialogBeforeClose"
      @open="onOpenAddPartDialogAsync"
    >
      <div v-loading="dialogIsLoading" :element-loading-text="dialogLoadingText">
        <div>
          <el-text>任务名称：</el-text>
          <el-input
            v-model="taskName"
            style="margin-top: 4px"
            maxlength="20"
            type="text"
            placeholder=""
          ></el-input>
        </div>
        <div style="margin-top: 10px">
          <el-text>设备名称：</el-text>
          <el-select filterable clearable v-model="deviceName">
            <el-option
              v-for="item in deviceConfigurations"
              :key="item.id"
              :label="item.deviceName"
              :value="item.deviceName"
            />
          </el-select>
        </div>
        <div style="margin-top: 10px">
          <el-text>地址：</el-text>
          <el-input v-model="address" style="margin-top: 4px" maxlength="20" type="text"></el-input>
        </div>
        <div style="margin-top: 10px">
          <el-text>数据类型：</el-text>
          <el-select filterable clearable v-model="dataType">
            <el-option v-for="item in dataTypes" :key="item" :label="item" :value="item" />
          </el-select>
        </div>
        <div style="margin-top: 10px">
          <el-text>扫描周期：</el-text>
          <el-input
            v-model="interval"
            style="margin-top: 4px"
            maxlength="20"
            type="number"
          ></el-input>
        </div>
        <div style="margin-top: 10px">
          <div style="float: left">
            <el-text>任务状态：</el-text>
            <el-switch v-model="enable" inline-prompt active-text="是" inactive-text="否" />
          </div>
          <div>
            <el-text style="padding-left: 10px">发布状态：</el-text>
            <el-switch v-model="published" inline-prompt active-text="是" inactive-text="否" />
          </div>
        </div>
        <div style="display: flex; justify-content: center; margin-top: 20px">
          <el-button type="primary" @click="onAddPollingTaskAsync">添加</el-button>
        </div>
      </div>
    </el-dialog>
  </main>
</template>
  

  <style lang="scss" scoped>
:deep(.el-divider--horizontal) {
  margin: 15px 0px 0px 0px;
}

.main-container {
  height: 100%;
  width: 100%;
  padding: 0px 15px 15px 15px;

  .main-content {
    height: 100%;
    width: 100%;
    display: flex;
    flex-direction: column;
    overflow: hidden;

    .search-bar {
      display: flex;
      flex-direction: row;
      align-items: center;
      justify-content: space-between;

      .select-container {
        display: flex;
        flex-direction: row;

        .select-margin {
          margin-left: 15px;
        }

        .select-layout {
          width: 240px;
          margin-left: 10px;
        }
      }
    }

    .table-content {
      flex-grow: 1;
      overflow: hidden;
      .table {
        height: 100%;
      }
    }
  }
}
</style>